package org.zh.sh.util;


import com.alibaba.fastjson2.JSON;

import java.io.*;
import java.lang.reflect.Array;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;

import static java.nio.file.FileVisitOption.FOLLOW_LINKS;


public class Utils {
    private Utils(){}
    private static final char FOLDER_SEPARATOR_CHAR = '/';
    private static final char DOT_CHAR = '.';

    public static void notNull(@Nullable Object object, String message) {
        if (object == null) {
            throw new IllegalArgumentException(message);
        }
    }

    public static boolean hasLength(@Nullable CharSequence str) {
        return (str != null && !str.isEmpty());  // as of JDK 15
    }

    public static boolean hasLength(@Nullable String str) {
        return (str != null && !str.isEmpty());
    }

    public static int copy(File in, File out) throws IOException {
        notNull(in, "文件不能为空");
        notNull(out, "文件不能为空");
        return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath()));
    }

    public static boolean hasText(@Nullable String str) {
        return (str != null && !str.isBlank());
    }

    public static void copy(byte[] in, File out) throws IOException {
        notNull(in, "文件不能为空");
        notNull(out, "文件不能为空");
        copy(new ByteArrayInputStream(in), Files.newOutputStream(out.toPath()));
    }

    public static byte[] copyToByteArray(File in) throws IOException {
        notNull(in, "文件不能为空");
        InputStream inputStream = Files.newInputStream(in.toPath());
        byte[] bytes = inputStream.readAllBytes();
        inputStream.close();
        return bytes;
    }

    public static int copy(InputStream in, OutputStream out) throws IOException {
        notNull(in, "文件不能为空");
        notNull(out, "文件不能为空");
        try (in; out) {
            int count = (int) in.transferTo(out);
            out.flush();
            return count;
        }
    }

    public static boolean isEmpty(@Nullable Object object) {
        if (object == null) {
            return true;
        }
        if (object instanceof CharSequence) {
            return ((CharSequence) object).isEmpty();
        }
        if (isArray(object)) {
            return Array.getLength(object) == 0;
        }
        return switch (object) {
            case Collection<?> objects -> objects.isEmpty();
            case Map<?, ?> map -> map.isEmpty();
            case Optional<?> o ->
                // TODO Java 11 Use Optional#isEmpty()
                    o.isEmpty();
            default -> false;
        };
    }

    public static boolean isArray(@Nullable Object object) {
        return object != null && object.getClass().isArray();
    }

    public static <K, V> Map<K, V> removeEmpty(Map<K, V> dataMap) {
        Iterator<Map.Entry<K, V>> iterator = dataMap.entrySet().iterator();
        if (iterator.hasNext()) {
            Map.Entry<K, V> next = iterator.next();
            V value = next.getValue();
            if (isEmpty(value)) {
                dataMap.remove(next.getKey());
            }
        }
        return dataMap;
    }

    public static String quote(@Nullable String str) {
        return (str != null ? "'" + str + "'" : null);
    }

    public static Object quoteIfString(@Nullable Object obj) {
        return (obj instanceof String str ? quote(str) : obj);
    }

    public static String getFilename(String path) {
        if (path == null) {
            throw new IllegalArgumentException("path not null");
        }
        int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR_CHAR);
        return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path);
    }

    public static String[] addStringToArray(@Nullable String[] array, String str) {
        if (array == null || array.length == 0) {
            return new String[]{str};
        }
        String[] newArr = new String[array.length + 1];
        System.arraycopy(array, 0, newArr, 0, array.length);
        newArr[array.length] = str;
        return newArr;
    }

    public static String getFilenameSuffix(@Nullable String path) {
        if (path == null) {
            return null;
        }

        int extIndex = path.lastIndexOf(DOT_CHAR);
        if (extIndex == -1) {
            return null;
        }

        int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR_CHAR);
        if (folderIndex > extIndex) {
            return null;
        }

        return path.substring(extIndex + 1);
    }

    public static boolean deletePath(@Nullable Path root) throws IOException {
        if (root == null) {
            return false;
        }
        if (!Files.exists(root)) {
            return false;
        }

        Files.walkFileTree(root, new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.delete(file);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
        });
        return true;
    }

    public static void copyPath(Path src, Path dest) throws IOException {
        notNull(src, "源文件必须存在");
        notNull(dest, "目标路径必须存在");
        BasicFileAttributes srcAttr = Files.readAttributes(src, BasicFileAttributes.class);
        if (srcAttr.isDirectory()) {
            Files.walkFileTree(src, EnumSet.of(FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    Files.createDirectories(dest.resolve(src.relativize(dir)));
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.copy(file, dest.resolve(src.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
                    return FileVisitResult.CONTINUE;
                }
            });
        } else if (srcAttr.isRegularFile()) {
            Files.copy(src, dest);
        }
    }

    public static boolean isEmpty(@Nullable Collection<?> collection) {
        return (collection == null || collection.isEmpty());
    }

    public static boolean isEmpty(@Nullable Map<?, ?> map) {
        return (map == null || map.isEmpty());
    }
    public static List<String> forJSON(List<String> list) {
        List<String> data = new ArrayList<>();
        for (String item : list) {
            data.add(String.format("\"%s\"", item));
        }
        return data;
    }

    public static void JSONPrint(Object... objs) {
        for (Object obj : objs) {
            System.out.println(JSON.toJSONString(obj));
        }
    }
    public static void JSONPrint0(Object... objs) {
            System.out.println(JSON.toJSONString(objs));

    }

}
